#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#       run.py
#       
#       Copyright 2012 José Roberto Colombo Junior <junior@Hohenheim>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import sys
import os
import codecs
import subprocess as sbp
import numpy as np
import pylab as plt
from PyQt4 import QtCore, QtGui
from QtSimulator import Ui_QtSimulator
from util import *
from os.path import isfile

class StartQT4(QtGui.QMainWindow):
	def __init__(self, parent=None):
		QtGui.QWidget.__init__(self, parent)
		self.ui = Ui_QtSimulator()
		self.ui.setupUi(self)
		if os.name == 'nt': # Se estiver no windows
			clique = "triggered()"
			
		else:
			clique = "activated()"
		
		# Menus	
		QtCore.QObject.connect(self.ui.actionSair,QtCore.SIGNAL(clique), self.close)
		QtCore.QObject.connect(self.ui.actionAbrir_esquematico,QtCore.SIGNAL(clique), self.abrir_esquematico)
		QtCore.QObject.connect(self.ui.actionAbrir_comandos,QtCore.SIGNAL(clique), self.abrir_comandos)
		QtCore.QObject.connect(self.ui.actionSalvar_arquivo_de_comandos,QtCore.SIGNAL(clique), self.salvar_comandos)
		QtCore.QObject.connect(self.ui.actionSimular,QtCore.SIGNAL(clique), self.simular)
		QtCore.QObject.connect(self.ui.actionEditar_esquematico,QtCore.SIGNAL(clique), self.editar_esquematico)
		QtCore.QObject.connect(self.ui.actionSobre,QtCore.SIGNAL(clique), self.about)
		
		# Botões
		QtCore.QObject.connect(self.ui.botao_aplicar,QtCore.SIGNAL("clicked()"), self.aplicar)
		
		# Eventos
		QtCore.QObject.connect(self.ui.ativar_ac, QtCore.SIGNAL("clicked()"), self.ativa_ac)
		QtCore.QObject.connect(self.ui.ativar_tran, QtCore.SIGNAL("clicked()"), self.ativa_tran)
		QtCore.QObject.connect(self.ui.textEdit, QtCore.SIGNAL("textChanged()"), self.texto_editado)
		QtCore.QObject.connect(self.ui.ploter, QtCore.SIGNAL("currentIndexChanged(int)"), self.ativa_arquivo_saida)
	
	# Essa função insere um * no texto do título da caixa de comandos, indicando que há alguma mudança no texto
	def texto_editado(self):
		self.ui.label.setText(u'Comandos a executar *');
		self.setWindowTitle(u'QtSimulator *')
	
	def ativa_arquivo_saida(self):
		estado = self.ui.ploter.currentIndex ()
		self.ui.label_8.setEnabled(estado)
		self.ui.arquivo_saida.setEnabled(estado)
	
	def ativa_tran(self):
		estado = self.ui.ativar_tran.isChecked ()
		self.ui.linha_tran_inicio.setEnabled(estado)
		self.ui.linha_tran_passo.setEnabled(estado)
		self.ui.linha_tran_fim.setEnabled(estado)
		self.ui.tempo_tran_inicio.setEnabled(estado)
		self.ui.tempo_tran_passo.setEnabled(estado)
		self.ui.tempo_tran_fim.setEnabled(estado)
		
		self.ui.tensao_corrente.setEnabled(estado)
		self.ui.controle_no.setEnabled(estado)
		self.ui.ploter.setEnabled(estado)
		self.ui.operacao.setEnabled(estado)
		self.ui.check_exit.setEnabled(estado)
		if (self.ui.ploter.currentIndex () == 1):
			self.ui.label_8.setEnabled(estado)
			self.ui.arquivo_saida.setEnabled(estado)
		
		else:
			self.ui.label_8.setEnabled(False)
			self.ui.arquivo_saida.setEnabled(False)
					
	def ativa_ac(self):
		estado = self.ui.ativar_ac.isChecked ()
		self.ui.linha_ac_inicio.setEnabled(estado)
		self.ui.linha_ac_fim.setEnabled(estado)
		self.ui.freq_ac_inicio.setEnabled(estado)
		self.ui.freq_ac_fim.setEnabled(estado)
		self.ui.decada_ac.setEnabled(estado)
		self.ui.numero_pontos.setEnabled(estado)
		
		self.ui.tensao_corrente.setEnabled(estado)
		self.ui.controle_no.setEnabled(estado)
		self.ui.ploter.setEnabled(estado)
		self.ui.operacao.setEnabled(estado)
		self.ui.check_exit.setEnabled(estado)
		if (self.ui.ploter.currentIndex () == 1):
			self.ui.label_8.setEnabled(estado)
			self.ui.arquivo_saida.setEnabled(estado)
		
		else:
			self.ui.label_8.setEnabled(False)
			self.ui.arquivo_saida.setEnabled(False)
						
	def abrir_esquematico(self):
		global caminho_completo
		
		fd = QtGui.QFileDialog(self)
		filename = fd.getOpenFileName(None, u'Abrir diagrama esquemático', '.', u'Arquivos gEDA (*.sch);;Mostrar todos (*)')
		
		if isfile(filename):
			# Carrega o arquivo para testar se o usuário incluiu a caixa spice-include.
			# Tal caixa é responsável por chamar o arquivo de comandos a ser criado pelo programa
			
			s = codecs.open(filename, 'r', 'utf-8').read()
			caminho = str(filename).split('/')
			caminho_completo = str(filename)
			del (caminho[0])
			del (caminho[len (caminho) -1])
			
			string_caminho = '/'
			for item in range(0, len (caminho)):
				string_caminho+= str(caminho[item]) + '/'
			
			if s.find('spice-include') == -1:
				novo_arquivo = s + spice_include()
				arquivo = open(filename, 'w')
				arquivo.write(novo_arquivo)
				arquivo.close()
			
			comando = 'gnetlist ' +  str(filename) + ' -g spice-sdb -o ' + string_caminho + 'netlist_temp.net'
			
			# Uma vez que o arquivo contém a caixa, deve-se gerar o netlist do mesmo
			if sbp.check_call([comando], shell=True) == 0:
				QtGui.QMessageBox.information(self, 'Sucesso!', u'Arquivo carregado com sucesso!', QtGui.QMessageBox.Ok)

			else:
				QtGui.QMessageBox.critical(self, 'Problema encontrado', u'Por favor, verifique o diagrama esquemático.', QtGui.QMessageBox.Ok)
	
	def editar_esquematico(self):
		global caminho_completo
		print caminho_completo

		# Abre o gEDA
		sbp.check_call(['gschem '+ caminho_completo], shell=True)
		
		# Temos que recriar o netlist
		caminho = caminho_completo.split('/')
		del (caminho[0])
		del (caminho[len (caminho) -1])
		string_caminho = '/'
		for item in range(0, len (caminho)):
				string_caminho+= str(caminho[item]) + '/'
		comando = 'gnetlist ' +  caminho_completo + ' -g spice-sdb -o ' + string_caminho + 'netlist_temp.net'
		if sbp.check_call([comando], shell=True) == 0:
				QtGui.QMessageBox.information(self, 'Sucesso!', u'Arquivo editado com sucesso!', QtGui.QMessageBox.Ok)

		else:
				QtGui.QMessageBox.critical(self, 'Problema encontrado', u'Por favor, verifique o diagrama esquemático.', QtGui.QMessageBox.Ok)
	
	# Função para abrir um arquivo com comandos
	def abrir_comandos(self):
		# Abre a caixa que receberá o nome do arquivo selecionado
		fd = QtGui.QFileDialog(self)
		nome = fd.getOpenFileName(None, u'Abrir arquivo de comandos', '.', u'Arquivos cmd (*.cmd);;Mostrar todos (*)')
		
		# Se o usuário selecionar um arquivo
		if isfile(nome):
			global filename
			filename = nome
			s = codecs.open(filename,'r','utf-8').read()
			self.ui.textEdit.setText (s)
			
			# Lê o arquivo e seleciona as opções pertinentes às caixas
			# Se houver um campo de análise de transitório
			if s.find('.TRAN') != -1:
				# Ativa o checkbutton do transitório
				self.ui.ativar_tran.setChecked (True)
				self.ativa_tran()
				
				# Procura pelos espaços inseridos após o campo .TRAN
				pos1_espaco = s.find(' ', s.find('.TRAN'))
				pos2_espaco = s.find(' ', pos1_espaco+1)
				pos3_espaco = s.find(' ', pos2_espaco+1)
				pos4_espaco = s.find(' ', pos3_espaco+1)
				
				# Seta as caixas
				# Seta o campo do passo
				passo = s[pos1_espaco+1:pos2_espaco]
				self.ui.linha_tran_passo.setText(passo.strip('smunp'))
				self.ui.tempo_tran_passo.setCurrentIndex(setar_caixa_tempo(passo.strip('1234567890,.')))
				
				# Seta o campo do fim
				fim = s[pos2_espaco+1:pos3_espaco]
				self.ui.linha_tran_fim.setText(fim.strip('smunp'))
				self.ui.tempo_tran_fim.setCurrentIndex(setar_caixa_tempo(fim.strip('1234567890,.')))
				
				# Seta o campo do início
				inicio = s[pos3_espaco+1:pos4_espaco]
				self.ui.linha_tran_inicio.setText(inicio.strip('smunp'))
				self.ui.tempo_tran_inicio.setCurrentIndex(setar_caixa_tempo(inicio.strip('1234567890,.')))
				
			# Se houver um campo de varredura em frequência AC
			if s.find('.AC') != -1:
				# Ativa o checkbutton do transitório
				self.ui.ativar_ac.setChecked (True)
				self.ativa_ac()
				
				# Muda a aba atual para AC
				self.ui.tabWidget.setCurrentIndex(1)
				
				# Procura pelos espaços inseridos após o campo .AC
				pos1_espaco = s.find(' ', s.find('.AC'))
				pos2_espaco = s.find(' ', pos1_espaco+1)
				pos3_espaco = s.find(' ', pos2_espaco+1)
				pos4_espaco = s.find(' ', pos3_espaco+1)
				pos5_espaco = s.find(' ', pos4_espaco+1)
				
				# Seta as caixas
				# Seta a caixa do tipo de década [DEC, OCT e LIN]
				decada = s[pos1_espaco+1:pos2_espaco]
				self.ui.decada_ac.setCurrentIndex(setar_decada(decada))
				
				# Seta o campo do número de pontos
				numero_de_pontos = s[pos2_espaco+1:pos3_espaco]
				self.ui.numero_pontos.setProperty("value", numero_de_pontos)
				
				# Seta o campo do início da varredura
				inicio = s[pos3_espaco+1:pos4_espaco]
				self.ui.linha_ac_inicio.setText(inicio.strip('HzkMGT'))
				self.ui.freq_ac_inicio.setCurrentIndex(setar_caixa_frequencia(inicio.strip('1234567890,.')))
				
				# Seta o campo do fim da varredura
				fim = s[pos4_espaco+1:pos5_espaco]
				self.ui.linha_ac_fim.setText(fim.strip('HzkMGT'))
				self.ui.freq_ac_fim.setCurrentIndex(setar_caixa_frequencia(fim.strip('1234567890,.')))
			
			# Seta o ploter utilizado, o arquivo de saída (se aplicável) e a operação
			if s.find('gnuplot') == -1:
				# Seta para plot
				self.ui.ploter.setCurrentIndex(0)
				
				# Seta o tipo de operação
				pos1_operacao = s.find('plot') +5
				pos2_operacao = s.find('(', pos1_operacao)
				operacao = setar_caixa_operacao (s[pos1_operacao:pos2_operacao])
				self.ui.operacao.setCurrentIndex(operacao)	
				
				# Seta o nome do nó
				pos1_noh = pos2_operacao +3
				pos2_noh = s.find(')', pos1_noh)
				self.ui.controle_no.setText(s[pos1_noh:pos2_noh])
				
				# Seta a caixa "Adicionar comando exit"
				if s.find('exit') != -1:
					self.ui.check_exit.setChecked (True)
			
			else: # gnuplot saida db(v(Vout))
				# Seta para gnuplot
				self.ui.ploter.setCurrentIndex(1)
				
				# Procura o primeiro espaço depois de gnuplot
				pos_gnuplot = s.find('gnuplot')
				pos1_nome_do_arquivo = s.find(' ', s.find(' ', pos_gnuplot)) +1
				pos2_nome_do_arquivo = s.find(' ', s.find(' ', pos_gnuplot)+1)
				
				# Encontra o nome do arquivo de saída
				nome_de_saida = s[pos1_nome_do_arquivo:pos2_nome_do_arquivo]
				self.ui.arquivo_saida.setText(nome_de_saida)
				
				# Nome do arquivo de saída
				operacao = setar_caixa_operacao (s[pos2_nome_do_arquivo+1:s.find('(', pos2_nome_do_arquivo)])
				self.ui.operacao.setCurrentIndex(operacao)	
				
				# Seta o nome do nó
				pos1_noh = s.find('(', pos2_nome_do_arquivo) + 3
				pos2_noh = s.find(')', pos1_noh)
				self.ui.controle_no.setText(s[pos1_noh:pos2_noh])
				
				# Seta a caixa "Adicionar comando exit"
				if s.find('exit') != -1:
					self.ui.check_exit.setChecked (True)
			
			# Remove o '*' do título:
			self.ui.label.setText(u'Comandos a executar');
			self.setWindowTitle(u'QtSimulator')
					
	def salvar_comandos(self):
		global filename
		
		s = str(self.ui.textEdit.toPlainText ())
		
		# Salva os dados em um arquivo já existente
		try :
			arquivo = codecs.open(filename,'w','utf-8')
			arquivo.write(s)
			arquivo.close()
			self.ui.label.setText("Comandos a executar");
			self.setWindowTitle(u'QtSimulator')
		
		# Criará um novo arquivo
		except:
			fd = QtGui.QFileDialog()
			fd.setLabelText (QtGui.QFileDialog.FileName, '&Nome do Arquivo')
			filename = fd.getSaveFileName(None, u'Abrir arquivo de comandos', '.', u'Arquivos cmd (*.cmd);;Mostrar todos (*)')
			
			if filename:
				arquivo = open(filename,'w','utf-8')
				arquivo.write(s)
				arquivo.close()
	
	def simular(self):
		global filename
		
		if filename:
			sbp.check_call(["ngspice -a netlist_temp.net"], shell=True)
		
		else:
			QtGui.QMessageBox.warning(self, 'Falha', u'Por favor, primeiro abra o arquivo.', QtGui.QMessageBox.Ok)
	
	def aplicar(self):
		if (self.ui.ativar_tran.isChecked () == True) or (self.ui.ativar_ac.isChecked () == True):
			if self.ui.ativar_tran.isChecked () == True:
				tran = '.TRAN ' + str(self.ui.linha_tran_passo.text ()) + caixa_tempo(self.ui.tempo_tran_passo.currentIndex ())
				tran+= str(self.ui.linha_tran_fim.text ()) + caixa_tempo(self.ui.tempo_tran_fim.currentIndex ())
				tran+= str(self.ui.linha_tran_inicio.text ()) + caixa_tempo(self.ui.tempo_tran_inicio.currentIndex ())
				ac = ''
			
			if self.ui.ativar_ac.isChecked () == True:
				ac = '.AC ' + decada (self.ui.decada_ac.currentIndex ()) + str(self.ui.numero_pontos.value ()) + ' '
				ac+= str(self.ui.linha_ac_inicio.text ()) + caixa_frequencia (self.ui.freq_ac_inicio.currentIndex ())
				ac+= str(self.ui.linha_ac_fim.text ()) + caixa_frequencia (self.ui.freq_ac_fim.currentIndex ())
				tran = ''
			
			controle = '\n\n.control\nset filetype=ascii\nrun\n'
			noh = noh_(self.ui.tensao_corrente.currentIndex(), unicode(self.ui.controle_no.text()))
			if self.ui.ploter.currentIndex () == 1: # Se for o gnuplot
				controle+= 'gnuplot ' + unicode(self.ui.arquivo_saida.text()) + ' '
				
			else:
				controle+= 'plot '
				
			controle+= caixa_operacao(self.ui.operacao.currentIndex(), noh)
			
			if self.ui.check_exit.isChecked () == True:
				controle+= '\nexit'
			
			controle+= '\n.endc'
				
			s = str(self.ui.textEdit.toPlainText ())
			self.ui.textEdit.setText (tran + ac + controle)
						
			if s == (tran + ac + controle):
				self.ui.label.setText("Comandos a executar");
				self.setWindowTitle(u'QtSimulator')
	
	def closeEvent(self, event):
		reply = QtGui.QMessageBox.question(self, 'Confirmar fechamento', "Tem certeza que deseja sair?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
		if reply == QtGui.QMessageBox.Yes:
			event.accept()
		else:
			event.ignore()
	
	def about(self):
		QtGui.QMessageBox.about(self, "Sobre o QtSimulator", u"QtSimulator 0.1 \n\nUma IDE para o simulador ngspice. \n\nDesenvolvido por José Roberto Colombo Junior")

if __name__ == "__main__":
	global s, filename
	s = filename = ''
	app = QtGui.QApplication(sys.argv)
	myapp = StartQT4()
	myapp.show()
	sys.exit(app.exec_())
